/**
 * @author Andrey Anisimov <hercules@inbox.ru>
 */

import core.util.AbstractTimer;

class FixedIntervalTimer extends AbstractTimer {

    /**
     * @public
     * @param interval {Number} (optional) Timer interval, in milliseconds (default is 1000).
     * @constructor
     */
    this.FixedIntervalTimer = function(interval) {
        super();
        this.interval = (interval !== undefined) ? interval : 1000;
        this.intervalHandler = bind(this, function() {
            this.fireTimer();
            this.restart(this.interval);
        });
    };

    /**
     * @public
     * @param interval {Number} Timer interval in millis
     */
    this.setInterval = function(interval) {
        this.interval = interval;
        if (this.startTime) {
            this.restart(interval - (Date.now() - this.startTime));
        }
    };

    /**
     * @public
     * @return {Number} Timer interval in millis.
     */
    this.getInterval = function() {
        return this.interval;
    };

    /**
     * @public
     */
    this.start = function() {
        this.fireStarted();
        this.timePassed = 0;
        this.timerId = this.setTimeout(this.intervalHandler, this.interval);
        this.startTime = Date.now();
    };

    /**
     * @public
     */
    this.stop = function() {
        if (this.timerId) {
            this.clearTimeout(this.timerId);
            delete this.timerId;
            delete this.startTime;
            delete this.timePassed;
            this.fireStopped();
        }
    };

    /**
     * @public
     */
    this.pause = function() {
        if (!this.timerId) {
            return;
        }
        this.clearTimeout(this.timerId);
        delete this.timerId;
        this.timePassed += (Date.now() - this.startTime);
        this.paused = true;
        this.firePaused();
    };

    /**
     * @public
     */
    this.resume = function() {
        if (!this.paused) {
            return;
        }
        this.timerId = this.setTimeout(this.intervalHandler, this.interval - this.timePassed);
        this.startTime = Date.now();
        this.paused = false;
        this.fireResumed();
    };

    /**
     * @public
     * @return {Boolean}
     */
    this.isStarted = function() {
        return this.timerId;
    };

    /**
     * @public
     * @return {Date}
     */
    this.getStartTime = function() {
        return this.startTime;
    };

    /**
     * @abstract
     * @protected
     * @param {Function} handler
     * @param {Number} timeout
     * @return {Object} timer ID
     */
    this.setTimeout = function(handler, timeout) {
        throw new Error('AbstractTimer.setTimeout is abstract!');
    };

    /**
     * @abstract
     * @protected
     * @param {Object} timerId
     */
    this.clearTimeout = function(timerId) {
        throw new Error('AbstractTimer.clearTimeout is abstract!');
    };

    /**
     * @private
     * @param timeout {Number}
     */
    this.restart = function(timeout) {
        if (this.timerId) {
             this.timePassed = 0;
            this.clearTimeout(this.timerId);
            this.timerId = this.setTimeout(this.intervalHandler, timeout);
            this.startTime = Date.now();
        }
    };
}